home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung 2
/
Power-Programmierung CD 2 (Tewi)(1994).iso
/
gnu
/
gnulib
/
sipp
/
doc
/
sipp.2
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
GNU Info File
|
1994-02-16
|
48.8 KB
|
1,397 lines
This is Info file sipp, produced by Makeinfo-1.55 from the input file
sipp.tex.
Copyright (C) 1992 Jonas Yngvesson, Inge Wallin
File: sipp, Node: Geometric operations, Next: Object transformations, Up: Transformations
Geometric operations
====================
To use the vector and matrix functions and macros definied in the
following section, you must include the following line into your
program:
#include <geometric.h>
In geometric.h include file, all data types, macros and functions
defined in this section are declared.
* Menu:
* Vector operations:: Operations on 3-dimensional vectors.
* Matrix operations:: Homogenous transformations defined on matrices
File: sipp, Node: Vector operations, Next: Matrix operations, Up: Geometric operations
Vector operations
-----------------
SIPP uses row vectors and not column vectors. A vector is defined as
follows:
typedef struct {
double x;
double y;
double z;
} Vector;
This vector type is used both for directional vectors and points
positional vectors. In the description below, lower case letters denote
scalar values and upper case letters denote vectors. All operations are
macros except the last one, `vecnorm()'.
`MakeVector(V, xx, yy, zz)'
Put `xx', `yy' and `zz' in the `x', `y' and `z' slot of the Vector
`V' respectively.
`VecNegate(A)'
Negate all components of the Vector `A'.
`VecDot(A, B)'
Return the dot product of the two Vectors `A' and `B'.
`VecLen(A)'
Return the length of the Vector `A'.
`VecCopy(A, B)'
Copy the Vector `B' to the Vector `A' (`A = B;' using C notation).
`VecAdd(C, A, B)'
Add the two Vectors `A' and `B' and put the result in `C' (`C = A
+ B;' using C notation).
`VecSub(C, A, B)'
Subtract the Vector `B' from Vector `A' and put the result in `C'
(`C = A - B;' using C notation).
`VecScalMul(B, a, A)'
Multiply the Vector `A' with the scalar `a' and put the result in
Vector `B' (`B = a * A;' using C notation).
`VecAddS(C, a, A, B)'
Multiply the Vector `A' with the scalar `a', add it to Vector `B'
and put the result in Vector `C' (`C = a * A + B;' using C
notation).
`VecComb(C, a, A, b, B)'
Linearly combine the two Vectors `A' and `B' and put the result in
Vector `C' (`C' = `a * A + b * B;' using C notation).
`VecCross(C, A, B)'
Cross multiply Vector `A' with Vector `B' and put the result in
`C' (`C = A' X `B;').
`void vecnorm(v)
'
`Vector *v;'
Normalize the vector `v', i.e. keep the direction but make it have
length 1. The length of `v' should not be equal to 0 to begin
with. *NOTE:* This is the only function operating on vectors in
sipp. All the other operations are macros.
File: sipp, Node: Matrix operations, Prev: Vector operations, Up: Geometric operations
Matrix operations
-----------------
An full homogenous transformation matrix has 4 x 4 elements.
However, all linear transformations use only 4 x 3 values so to save
space a SIPP transformation matrix only store 4 x 3 values. Also, if 4
x 4 matrices are used, all vectors must have 4 elements which we want
to avoid. Thus the transformation matrix used in sipp is defined as
follows:
typedef struct {
double mat[4][3];
} Transf_mat;
We wrap a `struct' around the two-dimensional array since we want to
be able to say things like `&mat' without being forced to write
`(Transf_mat *) &mat[0]' which we find horrendously ugly.
SIPP has a predefined identity matrix declared in geometric.h which
you can use:
extern Transf_mat ident_matrix;
The rest of this section describes the macro and functions defined in
the SIPP library which operate on SIPP transformation matrices.
`MatCopy(A, B)'
This macro copies the matrix `B' to the matrix `A'. `A' and `B'
must both be pointers. *NOTE:* This is the only macro operating on
matrices in SIPP. All other operations listed here are functions.
`Transf_mat *transf_mat_create(initmat)'
`Transf_mat *initmat;'
Allocate memory for a new transformation matrix and if `initmat' is
equal to `NULL', set the new matrix to the identity matrix.
Otherwise set the new matrix to the contents of `initmat'. Return
a pointer to the new matrix.
`Transf_mat *transf_mat_destruct(mat)'
`Transf_mat *initmat;'
Free the memory associated with the matrix `mat'.
`void mat_translate(mat, dx, dy, dz)'
`Transf_mat *mat;
double dx;
double dy;
double dz;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
translation along the vector (`dx', `dy', `dz').
`void mat_rotate_x(mat, ang)'
`Transf_mat *mat;
double ang;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
rotation with the angle `ang' around the X axis. The angle `ang'
is expressed in radians.
`void mat_rotate_y(mat, ang)'
`Transf_mat *mat;
double ang;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
rotation with the angle `ang' around the Y axis. The angle `ang'
is expressed in radians.
`void mat_rotate_z(mat, ang)'
`Transf_mat *mat;
double ang;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
rotation with the angle `ang' around the Z axis. The angle `ang'
is expressed in radians.
`void mat_rotate(mat, point, vector, ang)'
`Transf_mat *mat;
Vector *point;
Vector *vector;
double ang;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
rotation with the angle `ang' around the line represented by the
point `point' and the vector `vector'. The angle `ang' is
expressed in radians.
`void mat_scale(mat, xscale, yscale, zscale)'
`Transf_mat *mat;
double xscale;
double yscale;
double zscale;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a scaling
with the scaling factors (`xscale', `yscale', `zscale').
`void mat_mirror_plane(mat, point, normal)'
`Transf_mat *mat;
Vector *point;
Vector *normal;'
Set `mat' to the transformation matrix that represents the
concatenation of the previous transformation in `mat' and a
mirroring in the plane defined by the point `point' and the normal
vector `normal'.
`void mat_mul(res, a, b)'
`Transf_mat *res;
Transf_mat *a;
Transf_mat *b;'
Multiply the two matrices `a' and `b' and put the result in the
matrix `res'. All three parameters are pointers to matrices. It
is possible for `res' to point at the same matrix as either `a' or
`b' since the result is stored in a temporary matrix during the
computations.
`void point_transform(res, vec, mat)'
`Vector *res;
Vector *vec;
Transf_mat *mat;'
Transform the point (vector) `vec' with the transformation matrix
`mat' and put the result into the vector `res'. The two vectors
`res' and `vec' should not be the same vector since no temporary
is used during the computations.
File: sipp, Node: Object transformations, Prev: Geometric operations, Up: Transformations
Object transformations
======================
There are two functions for reading and writing such matrices from
and to objects:
Transf_mat *
object_get_transf(object, matrix)
Object *object;
Transf_mat *matrix;
This function retrieves the transformation matrix of the object
pointed to by `object'. If `matrix' is `NULL' the function will
allocate space for a matrix, copy the object's matrix into this space
and return a pointer to the new matrix. If `matrix' is not `NULL' the
objects transformation matrix is copied into the space its pointing to
and the same pointer is returned.
void
object_set_transf(object, matrix)
Object *object;
Transf_mat *matrix;
This function copies the matrix pointed to by `matrix' into
`object''s transformation matrix.
There is also a special function for resetting an object's
transformation matrix to the identity matrix, i.e. no transformation at
all:
void
object_clear_transf(object)
Object *object;
Applying transformations
------------------------
The transformations in this section are all applied to an object
without altering its previous transformations, i.e. they will be
applied after the previous transformations have been completed. What
actually happens is that the matrix that specifies the new
transformation is post multiplied into the objects current matrix.
There are four functions for rotating objects:
void
object_rot_x(object, angle)
Object *object;
double angle;
void
object_rot_y(object, angle)
Object *object;
double angle;
void
object_rot_z(object, angle)
Object *object;
double angle;
void
object_rot(object, point, vector, angle)
Object *object;
Vector *point;
Vector *vector;
double angle;
The first three functions rotate an object about one of the primary
axes in the parent object's local coordinate system. `angle' is the
rotation angle given in radians. Positive rotation is given by the
"right hand rule", i.e. counterclockwise when looking along the axis
towards the origin.
The fourth function is a more general rotation. It specifies a
rotation of an object about an arbitrary axis. The axis is defined as
passing through `point' in the direction of `vector', both are
described in the parent object's local coordinate system. `angle' is
the rotation angle in radians and positive rotation is defined in the
same way as for the previous three functions.
For scaling an object the following function is used:
void
object_scale(object, sx, sy, sz)
Object *object;
double sx, sy, sz;
The object pointed to by `object' is scaled towards the origin along
the three principal axes with the three scaling factors `sx, sy' and
`sz' respectively.
The last standard transformation is translation:
void
object_move(object, dx, dy, dz)
Object *object;
double dx, dy, dz;
The object is translated along the vector (`dx dy dz') from its
current position. Note that the movement is relative and not absolute.
The translation vector is given in the parent coordinate system.
There is also a general transformation function that post-multiplies
any transformation matrix into the current matrix of an object:
void
object_transform(object, matrix)
Object *object;
Transf_mat *matrix;
File: sipp, Node: Lights, Next: Shadows, Prev: Transformations, Up: Top
Lights
******
SIPP supports two basic kinds of lights, simple lightsources and
spotlights. The main difference is that spotlights can cast shadows,
while simple lightsources can not. The functions that create any of
these lights return a pointer to a `Lightsource' structure. This
pointer is used for later manipulations of the light such as moving it
or turning it off or on. If there is no need for later manipulations
these pointers can safely be discarded. SIPP keeps track of all created
lightsources internally.
* Menu:
* Creating lights:: Creating lightsources and spotlights.
* Manipulating lights:: Changing already existing lights.
File: sipp, Node: Creating lights, Next: Manipulating lights, Up: Lights
Creating lights
===============
Simple lightsources can be of two types, directional and point
lightsources. Directional lightsources emit light that is parallel in
every point in the scene, similar to light from the sun. Point
lightsources emit light from a single point in space.
Lightsource *
lightsource_create(x, y, z, red, green, blue, type)
double x, y, z;
double red, green, blue;
int type;
* `x, y, z'
If a directional lightsource is created these numbers specifies a
vector pointing to the lightsource. If it is a point lightsource
the numbers specify the exact location of it.
* `red, green, blue'
These numbers indicate the color of the emitted light. All three
should be in the range [0, 1].
* `type'
This parameter defines which type of lightsource that is created.
It should be one of the predefined values `LIGHT_DIRECTION' or
`LIGHT_POINT'.
A spotlight emits a "cone" of light. There are two types of
spotlights in SIPP. One has a sharp edge on its lightcone and the other
has a soft edge that blends out smoothly. Rendering scenes with soft
edged spotlights takes slightly longer time than scenes with only sharp
edged spotlights.
Lightsource *
spotlight_create(x1, y1, z1, x2, y2, z2, opening, red, green, blue,
type, shadow)
double x1, y1, z1;
double x2, y2, z2;
double opening;
double red, green, blue;
int type;
bool shadow;
* `x1, y1, z1'
This is the position of the spotlight.
* `x2, y2, z2'
This is a point at which the spotlight is pointing. It is in the
middle of the lightcone.
* `opening'
This defines, in degrees, the opening angle of the lightcone. The
cone defined will be completely lit, a soft edged lightcone will
start to blend out outside this angle.
* `red, green, blue'
The color of the emitted light. All three numbers are in the range
[0, 1].
* `type'
Tells SIPP which type of spotlight to create. Should be one of the
predefined values `SPOT_SHARP' or `SPOT_SOFT'.
* `shadow'
If `TRUE', the light from the spotlight will be able to cast
shadows, otherwise not. Whether shadows actually are cast or not
depend on which value `sipp_shadows()' (*Note Initializations::)
was called with last.
There is also a function for releasing the memory used by a
lightsource or a spotlight.
void
light_destruct(light)
Lightsource *light;
* `light'
Pointer to the lightsource or spotlight that is to be destructed.
File: sipp, Node: Manipulating lights, Prev: Creating lights, Up: Lights
Manipulating lights
===================
When lights have been created they can be manipulated in various
ways. There are functions that are specific for lightsources, functions
specific for spotlights and generic functions which works for both kind
of lights.
void
lightsource_put(lightsrc, x, y, z)
Lightsource *lightsrc;
double x, y, z;
This function is used to modify the direction, or position, of a
lightsource. If (`x, y, z') are interpreted as a position or as a
direction vector depends on whether `lightsrc' is pointing at a point
lightsource or a directional lightsource.
void
spotlight_pos(spot, x, y, z)
Lightsource *spot;
double x, y, z;
Modify the position of a spotlight.
void
spotlight_at(spot, x, y, z)
Lightsource *spot;
double x, y, z;
Modify the position the spotlight is pointing at.
void
spotlight_opening(spot, opening)
Lightsource *spot;
double opening;
Modify the opening angle of the lightcone of a spotlight. `opening'
is given in degrees.
void
spotlight_shadows(spot, flag)
Lightsource *spot;
bool flag;
Turn shadow casting on or off for a specific spotlight. `flag' set
to `TRUE' means that the spotlight can cast shadows.
void
light_color(light, red, green, blue)
Lightsource *light;
double red, green, blue;
Change the color of the emitted light from a lightsource or a
spotlight. (`red, green, blue') are all numbers in the range [0, 1].
void
light_active(light, flag)
Lightsource *light;
bool flag;
Turn a lightsource or a spotlight on or off. If `flag' is `TRUE' the
light is activated.
The last function is not really a manipulation function. It evaluates
how much light from a certain lightsource or spotlight that reaches a
specific point in the scene. It also calculates a vector pointing from
this point at the light. The return value is a number in the range [0,
1] where 1 means that all light from the lightsource reaches the point
and 0 means that none of the light reaches it. The function is intended
to be used in shading functions. We describe it formally here and
refer to the chapter on how to write your own shaders for instructions
and examples of how to use it (*Note Writing your own shaders::).
double
light_eval(light, position, light_vector)
Lightsource *light;
Vector *position;
Vector *light_vector;
* `light'
Pointer to the lightsource or spotlight to evaluate.
* `position'
Pointer to a vector specifying which point in the scene we want to
check the illumination for. The position is given in the world
coordinate system.
* `light_vector'
Points to a space where `light_eval()' will store a normalized
vector pointing from `position' at the light.
File: sipp, Node: Shadows, Next: Viewpoint and cameras, Prev: Lights, Up: Top
Shadows
*******
SIPP creates shadows with a technique called depth maps. A detailed
description of this technique can be found in the article Rendering
Antialiased Shadows with Depth Maps by Reeves, Salesin and Cook in the
Proceedings of SIGGRAPH 1987.
In principle, a depth map is generated for each light that should
cast shadows. The depth map is simply an image of the scene, as seen
from the light, but instead of a color we store the depth (Z-buffer
value) in each "pixel". The finished map will contain the distance to
the object closest to the light in each point.
When the scene is rendered we transform each point we are shading
into depth map coordinates and if it is further away from the light
than the value stored in the corresponding point in the depth map, the
point is in shadow. The actual implementation is of course a bit more
complicated with some sampling and filtering but we won't go into that.
The reason we describe this algorithm at all is that it is easier to
understand how to get good looking shadows and why shadows sometimes
look weird if one have an understanding of the underlying process.
First of all: The shadows are generated by sampling in the depth
maps. Sampling usually means we are in danger of aliasing and this is
very true in our case. SIPP automatically fits the depth map for a
spotlight so that it covers all area lit by the spotlight's light cone
(*Note Creating lights::). If this area is large and the depth map
resolution is low, the shadows will get very jagged.
Also, if we have a large surface that is close to perpendicular to
the depth map plane, the depth map "pixels" will be projected as long
stripes on that surface, so even if the depth map resolution is high, a
shadow cast on such a surface will suffer from aliasing (be jagged).
So, if the edges of a shadow look weird, try increasing the size of
the depth map (the depth map size is set with `sipp_shadows()', *Note
Initializations::). If they still look weird, or you run out of memory,
try changing the position of the lightsource that generate the shadow.
After some tweaking it is usually possible to get fairly decent shadows.
File: sipp, Node: Viewpoint and cameras, Next: Rendering, Prev: Shadows, Up: Top
Viewpoint and cameras
*********************
The viewpoint model used in SIPP are a fairly standard one. A point
where the camera is located, a point which the camera looks at, a vector
telling which direction is up and the focal distance in the camera. The
user can create several virtual cameras and tell SIPP to use any of
them as viewpoint when rendering an image. There is also a predefined
camera called `sipp_camera' which is the default viewpoint. When
`sipp_init()' is called, this camera is initialized to be located in (0
0 10), looking at the origin, with the world y-axis as the up direction
and a focal factor (see below) of 0.25. The user can of course change
these values to whatever he likes.
To create and manipulate cameras, SIPP provide the following
functions:
Camera *
camera_create()
This function creates a new virtual camera and initializes it to the
same default setting as `sipp_init()' does with `sipp_camera' (see
above).
void
camera_destruct(camera)
Camera *camera;
Release the memory used by a virtual camera. `sipp_camera' can't be
destructed and if the camera which is currently used as viewpoint is
destructed, the current viewpoint will be reset to `sipp_camera'.
void
camera_position(camera, x, y, z)
Camera *camera;
double x, y, z;
Place `camera' at the position (`x, y, z') in the world coordinate
system.
void
camera_look_at(camera, x, y, z)
Camera *camera;
double x, y, z;
Set `camera' to look at the point (`x, y, z') in the world
coordinate system.
void
camera_up(camera, x, y, z)
Camera *camera;
double x, y, z;
Set the up direction of `camera' to be the vector (`x, y, z') in the
world coordinate system. The up direction is not allowed to be parallel
to the viewing direction, i.e. the vector from the camera position to
the point it is looking at.
void
camera_focal(camera, focal)
Camera *camera;
double focal;
Set `camera''s focal factor to be `focal'. The focal factor is the
ratio between half the screen height and the distance from the
viewpoint to the screen. Another way of describing it is tan(v/2) where
v is the opening angle of the view. A large focal factor will result in
a wide angle view while a small factor will give a telescopic effect.
See figure below:
screen
|
| s
viewpoint |
*-----------------------|
d |
|
|
focal = s / d
void
camera_params(camera, x1, y1, z1, x2, y2, z2, ux, uy, uz, focal)
Camera *camera;
double x1, y1, z1;
double x2, y2, z2;
double ux, uy, uz;
double focal;
Set all parameters of a camera in one call. (`x1, y1, z1') is the
position, (`x2, y2, z2') is the point the camera is looking at, (`ux,
uy, uz') is the up direction and `focal' is the focal factor. Note that
the up direction is not allowed to be parallel to the viewing
direction, i.e. the vector from the camera position to the point it is
looking at.
void
camera_use(camera)
Camera *camera;
Tell SIPP to use `camera' as the current viewpoint.
File: sipp, Node: Rendering, Next: Shaders, Prev: Viewpoint and cameras, Up: Top
Rendering
*********
SIPP can render images in four different modes:
* `PHONG' rendering interpolates surface normal and texture
coordinates across polygons and calls the appropriate shading
function in each point. This mode is the slowest but produces the
best results and is the only mode where any texturing effects can
be used. Note that most of the interesting effects that is
possible to produce with SIPP, e.g. shadows and position dependent
light (spotlights, point lights), are in fact texturing effects.
* `GOURAUD' rendering only calls the shader in the vertices of the
polygons and then interpolates the calculated colors across them.
The opacities returned from the shader is interpolated in the same
manner.
* `FLAT' rendering calls the shader once per polygon and then fills
the whole polygon with the resulting color. The whole polygon will
also get the opacity returned from the shader.
* `LINE' rendering will produce a monochrome line image with only the
edges of the polygons drawn. No shaders are involved. No hidden
line elimination are performed but backfacing polygons are not
drawn unless specifically ordered with `sipp_show_backfaces()'
(*Note Initializations::). There are two ways of rendering the
currently specified scene. They differ in the place to which the
rendered image is sent.
* Menu:
* Rendering to file:: Rendering into a PPM or PBM file.
* Rendering to other devices:: Rendering with a user specified function
* Rendering to in-core images:: Rendering to an image in memory
File: sipp, Node: Rendering to file, Next: Rendering to other devices, Up: Rendering
Rendering to file
=================
There are two functions for rendering into a file.
void
render_image_file(width, height, file, mode, oversampling)
int width, height;
FILE *file;
int mode;
int oversampling;
* `width, height'
These parameters specify the size of the image in pixels. If the
two sizes are different, the focal factor of the camera (*Note
Viewpoint and cameras::) is defined to refer to the smaller of the
two.
* `file'
This is a pointer to an open file on which the image will be
written. If the system supports it, it could just as well be a
pipe or a socket of course.
* `mode'
This defines the rendering mode, `LINE', `FLAT', `GOURAUD' or
`PHONG' as described earlier.
* `oversampling'
This parameter defines how much oversampling should be performed
for anti-aliasing. Each pixel will be rendered internally as a
mesh of (`oversampling x oversampling') subpixels and the average
color in this mesh will be used to represent the final pixel. This
parameter is ignored in `LINE' mode.
The other function for rendering into a file is useful when doing
animations. Since video formats are usually interlaced, it is possible
to get a smoother motion if each field (half-frame) is rendered
separately and the motion is updated between these fields instead of
between frames. Unfortunately `LINE' rendering can not be used when
rendering fields.
void
render_field_file(width, height, file, mode, oversampling, field)
int width, height;
FILE *file;
int mode;
int oversampling;
int field;
* `width, height'
These parameters specify the size of the image in pixels. It is the
height of the frame that should be specified in `height', not the
field, the field height is determined internally.
* `file'
This is a pointer to an open file on which the field will be
written. If the system supports it, it could just as well be a
pipe or a socket of course.
* `mode'
This defines the rendering mode, `FLAT', `GOURAUD' or `PHONG' as
described earlier.
* `oversampling'
This parameter defines how much oversampling should be performed
for anti-aliasing.
* `field'
This defines if an odd or even field should be produced. The value
should be one of the predefined constants `ODD' or `EVEN'. `ODD'
will result in only odd scanlines being rendered, with 0 being the
top scanline.
File: sipp, Node: Rendering to other devices, Next: Rendering to in-core images, Prev: Rendering to file, Up: Rendering
Rendering to other devices
==========================
Sometimes one does not want the rendered image to be stored in a
file. Perhaps it should be displayed in a window or further processed
in some way. SIPP provides a way to have a function called for each
rendered pixel, or for each line if a line image is rendered. The
function is given information about which pixel it is and what
resulting color it got. Since one of the most used applications of
this probably is rendering to a pixmap in memory, SIPP has special
support for that. *Note Rendering to in-core images::.
Use a call to the following function to render to another device
than a file:
void
render_image_func(width, height, pix_func, data, mode, oversampling)
int width, height;
void (*pix_func)();
void *data;
int mode;
int oversampling;
* `width, height'
These parameters specify the size of the image in pixels. If the
two sizes are different, the focal factor of the camera (*Note
Viewpoint and cameras::) is defined to refer to the smaller of the
two.
* `pix_func'
This is a pointer to a function that SIPP calls once for each
rendered pixel. If `LINE' rendering is used it is called for each
line instead. The function must have the following interface:
void
my_pixel_function(data, col, row, red, green, blue)
my_data *data;
int col, row;
unsigned char red, green, blue;
* `data' This is the same `data' pointer that was passed to
`render_image_func()'.
* `col, row' Specifies position of the pixel. (0, 0) is upper
left.
* `red, green, blue' This is the color of the pixel quantified
to 24 bits, 8 bits for each of red, green and blue.
If `LINE' rendering is used instead, the user provided function is
called for each rendered line instead of each pixel and should
have the following interface:
void
my_line_function(data, col1, row1, col2, row2)
my_data *data;
int col1, row1;
int col2, row2;
* `data' This is the same `data' pointer that was passed to
`render_image_func()'.
* `row1, col1, row2, col2' Specification of the two endpoints
of the line. (0, 0) is upper left,
* `data'
This is a pointer to any data structure that the pixel function
(see next item) needs. It could be a pointer to a specific pixmap
or window or whatever.
* `mode'
This defines the rendering mode, `LINE', `FLAT', `GOURAUD' or
`PHONG' as described earlier.
* `oversampling'
This parameter defines how much oversampling should be performed
for anti-aliasing. Each pixel will be rendered internally as a
mesh of (`oversampling x oversampling') subpixels and the average
color in this mesh will be used to represent the final pixel. This
parameter is ignored in `LINE' mode.
There is also a corresponding function to `render_field_file()' for
rendering a field into a user defined place. As in that function,
`LINE' rendering can not be used when rendering fields.
void
render_field_func(width, height, pix_func, data, mode, oversampling, field)
int width, height;
void (*pix_func)();
void *data;
int mode;
int oversampling;
int field;
All parameters have the same meaning as in `render_image_func()'
except the last one.
* `field'
This defines if an odd or even field should be produced. The value
should be one of the predefined constants `ODD' or `EVEN'. `ODD'
will result in only odd scanlines being rendered, with 0 being the
top scanline.
File: sipp, Node: Rendering to in-core images, Prev: Rendering to other devices, Up: Rendering
Rendering to in-core images
===========================
To people who want to create images in memory, we provide two image
formats similar in kind to the Portable Pixmap (ppm) and Portable Bitmap
(pbm). Only very simple operations are defined on them, but the
definition of the types are also given here, so those who want to write
their own functions operating on the images can do so.
* Menu:
* Sipp_pixmap:: The pixmap type (24 bits/pixel)
* Sipp_bitmap:: The pixmap type (1 bit/pixel)
File: sipp, Node: Sipp_pixmap, Next: Sipp_bitmap, Up: Rendering to in-core images
The Sipp_pixmap image data type
-------------------------------
To use the pixmap operations you must put the following line into
your source file:
#include <sipp_pixmap.h>
In this include file, the `Sipp_pixmap' data type is defined as well
as all operations operating on it. Only the most basic operations are
defined.
A `Sipp_pixmap' is defined like this:
typedef struct {
int width; /* Width of the pixmap */
int height; /* Height of the pixmap */
unsigned char * buffer; /* A pointer to the image. */
} Sipp_pixmap;
The pointer `buffer' is a pointer to the image where each pixel is
stored as three unsigned chars in the order red, green, blue. Thus, the
buffer is 3 * `width' * `height' bytes long.
The following functions are defined for a `Sipp_pixmap':
Sipp_pixmap *
sipp_pixmap_create(width, height)
int width;
int height;
Returns a newly created `Sipp_pixmap' with the given size. The new
pixmap is filled with zeros on creation.
void
sipp_pixmap_destruct(pm)
Sipp_pixmap *pm;
Frees all memory associated to the `Sipp_pixmap pm' and returns it
to the heap.
void
sipp_pixmap_set_pixel(pm, col, row, red, grn, blu)
Sipp_pixmap *pm;
int col;
int row;
unsigned char red;
unsigned char grn;
unsigned char blu;
Set the pixel at (`col', `row') in pixmap `pm' to be the color
(`red', `grn', `blu'). (0, 0) is upper left. Note that this function
is directly usable in `render_image_func()' defined in *Note Rendering
to other devices::, when using the `FLAT', `GOURAUD' or `PHONG' mode of
rendering.
void
sipp_pixmap_write(file, pm)
FILE *file;
Sipp_pixmap *pm;
Write the pixmap `pm' to the open file `file'. The image is written
in the Portable Pixmap format P6 (raw ppm), the same format SIPP is
using when rendering to a file.
File: sipp, Node: Sipp_bitmap, Prev: Sipp_pixmap, Up: Rendering to in-core images
The Sipp_bitmap image data type
-------------------------------
To use the pixmap operations you must put the following line into
your source file:
#include <sipp_bitmap.h>
In this include file, the `Sipp_bitmap' data type is defined as well
as all operations operating on it. Only the most basic operations are
defined.
A `Sipp_bitmap' is defined like this:
typedef struct {
int width; /* Width of the bitmap in pixels */
int height; /* Height of the bitmap in pixels */
int width_bytes; /* Width of the bitmap in bytes. */
unsigned char * buffer; /* A pointer to the image. */
} Sipp_bitmap;
The pointer `buffer' is a pointer to the image where each pixel is a
bit in an unsigned char, eight pixels per char. If the `width' field
is not a multiple of 8, the last bits in the last byte of a row are not
used. The most significant bit in each byte is the leftmost pixel. The
entire buffer is `width_bytes' * `height' bytes long.
The following functions operate on a `Sipp_bitmap':
Sipp_bitmap *
sipp_bitmap_create(width, height)
int width;
int height;
Returns a new `Sipp_bitmap' with the given size. The new bitmap is
filled with zeros on creation.
void
sipp_bitmap_destruct(bm)
Sipp_bitmap *bm;
Frees all memory associated to the `Sipp_bitmap bm' and returns it
to the heap.
void
sipp_bitmap_line(bm, col1, row1, col2, row2)
Sipp_bitmap *bm;
int col1;
int row1;
int col2;
int row2;
Draw a line from (`col1', `row1') to (`col2', `row2') in the bitmap
`bm'. (0, 0) is upper left. Note that this function is directly usable
in `render_image_func()' defined in *Note Rendering to other devices::,
when using the `LINE' mode of rendering.
void
sipp_bitmap_write(file, bm)
FILE *file;
Sipp_bitmap *bm;
Write the bitmap `bm' to the open file `file'. The image is written
in the Portable Bitmap format P4 (pbm), the same format SIPP is using
when rendering a line drawing to a file.
File: sipp, Node: Shaders, Next: Object primitives, Prev: Rendering, Up: Top
Shaders
*******
A major feature in SIPP is the very flexible way shading functions
are handled. Each surface has a pointer to a function that is called
whenever a point on that surface is rendered. The interface to these
shading functions is well defined so it is quite easy for a user to
write his own. SIPP also provides a number of shaders in the library for
various effects.
* Menu:
* Provided shaders:: Shaders provided with the library
* Writing your own shaders:: How to write your own shading functions
File: sipp, Node: Provided shaders, Next: Writing your own shaders, Up: Shaders
Provided shaders
================
This section describes all the shaders that are provided with SIPP.
To use any of them, except `basic_shader()', the program must contain
the following line:
#include <shaders.h>
The most important thing to know when using a shader is how it
represents its surface description and what this description should
contain. All provided shaders in SIPP use a normal C struct as surface
description.
* Menu:
* The basic shader:: The basic shader used by most of the rest of
the shaders
* The Phong shader:: The standard Phong shading model.
* The Strauss shader:: More realistic shader by Paul Strauss.
* The marble shader:: A shader creating a marble pattern
* The granite shader:: A shader creating a granite like pattern
* The wood shader:: A shader creating a wooden pattern
* The bozo shader:: A somewhat whimsical shader creating a pattern
originally used by Bozo the clown.
* The mask shader:: A shader usable when the contents of a mask
should control which one of two shaders will
determine the color of each pixel.
* The bumpy shader:: A shader which creates the illusion of a bumpy
surface
* The planet shader:: Creates a 3-dimensional pattern of a planet surface
File: sipp, Node: The basic shader, Next: The Phong shader, Up: Provided shaders
The basic shader
----------------
The basic shader in SIPP, `basic_shader()', is basically a Phong
shader but, with some influence from Blinn, the "shinyness" of the
surface is described with a number in the range [0, 1] and the
implemented "shinyness" function changes with this constant in a more
natural way (at least in our opinion).
Surface description:
typedef struct {
double ambient;
double specular;
double c3;
Color color;
Color opacity;
} Surf_desc;
* `ambient' is a number in the range [0, 1] specifying how much of
the surface color that is visible when the object is not lit by any
lightsource.
* `specular' is a number in the range [0, 1] specifying how much
light that is reflected in a specular highlight on the surface.
* `c3' is also a number in the range [0, 1]. It specifies how
"shiny" the surface is. 0 means a very shiny surface while 1
indicates a rather dull one.
* `color' is simply the color of the surface.
* `opacity' specifies how opaque the surface is. This is stored as a
color to allow different opacities for the different color bands.
The values should be in the range [0, 1] with 1 indicating a
completely opaque object and 0 a completely transparent
(invisible) one.
File: sipp, Node: The Phong shader, Next: The Strauss shader, Prev: The basic shader, Up: Provided shaders
The Phong shader
----------------
`phong_shader()' implements the well known Phong illumination model.
Surface description:
typedef struct {
double ambient;
double diffuse;
double specular;
int spec_exp;
Color color;
Color opacity;
} Phong_desc;
* `ambient' is a number in the range [0, 1] specifying how much of
the surface color that is visible when the object is not lit by any
lightsource.
* `diffuse' is a number in the range [0, 1] specifying how much
light that is reflected diffusely from the surface.
* `specular' is a number in the range [0, 1] specifying how much
light that is reflected in a specular highlight on the surface.
* `spec_exp' is the exponent in the specular highlight calculation.
It specifies how "shiny" the surface is. Useful values are about 1
to 200, where 1 is a rather dull surface and 200 is a very shiny
one.
* `color' is the color of the surface.
* `opacity' specifies how opaque the surface is. This is stored as a
color to allow different opacities for the different color bands.
The values should be in the range [0, 1] with 1 indicating a
completely opaque object and 0 a completely transparent
(invisible) one.
File: sipp, Node: The Strauss shader, Next: The marble shader, Prev: The Phong shader, Up: Provided shaders
The Strauss shader
------------------
`strauss_shader()' is a shader designed by Paul Strauss at Silicon
Graphics Inc. and published in IEEE CG&A Nov. 1990. In his article he
explains that most shading models in use today, e.g. Phong,
Cook-Torrance, are difficult to use for non-experts, and this for
several reasons. The parameters and their effect on a surface are non-
intuitive and/or complicated. The shading model Strauss designed has
parameters that is easy to grasp and have a reasonably deterministic
effect on a surface, but yet produces very realistic results.
Surface description:
typedef struct {
double ambient;
double smoothness;
double metalness;
Color color;
Color opacity;
} Strauss_desc;
* `ambient' is a number in the range [0, 1] specifying how much of
the surface color that is visible when the object is not lit by any
lightsource.
* `smoothness' is a number in the range [0, 1] that describes how
smooth the surface is. This parameter controls both diffuse and
specular reflections. 0 means a dull surface while 1 means a very
smooth and shiny one.
* `metalness' is a number in the range [0, 1]. It describes how
metallic the material is. It controls among other things how much
of the surface color should be mixed into the specular reflections
at different angles. 0 means a non-metal while 1 means a very
metallic surface.
* `color' is the color of the surface.
* `opacity' specifies how opaque the surface is. This is stored as a
color to allow different opacities for the different color bands.
The values should be in the range [0, 1] with 1 indicating a
completely opaque object and 0 a completely transparent
(invisible) one.
File: sipp, Node: The marble shader, Next: The granite shader, Prev: The Strauss shader, Up: Provided shaders
The marble shader
-----------------
`marble_shader()' uses a three dimensional texture to create the
appearance of marble. The texture is created by mixing distorted strips
of one color into another "base" color of the surface.
Surface description:
typedef struct {
double ambient;
double specular;
double c3;
double scale;
Color base;
Color strip;
Color opacity;
} Marble_desc;
* `ambient, specular, c3' and `opacity' have the same meaning as in
`basic_shader()' (see *Note The basic shader::).
* `scale' describes how much the texture coordinates should be scaled
before applying the texture. When scaling get larger, the object
will get larger in comparison to the marble pattern.
* `base' is the base color of the surface.
* `strip' is the color of the strips which is mixed in with the base
color.
File: sipp, Node: The granite shader, Next: The wood shader, Prev: The marble shader, Up: Provided shaders
The granite shader
------------------
`granite_shader()' is very similar to `marble_shader()'. It also
mixes two colors to create a three dimensional texture, but the mixing
is done in a different manner so the result should look like granite.
Surface description:
typedef struct {
double ambient;
double specular;
double c3;
double scale;
Color col1;
Color col2;
Color opacity;
} Granite_desc;
* `ambient, specular, c3' and `opacity' have the same meaning as in
`basic_shader()' (see *Note The basic shader::).
* `scale' describes how much the texture coordinates should be scaled
before applying the texture. When scaling get larger, the object
will get larger in comparison to the granite pattern.
* `col1' and `col2' are the two colors that are mixed.
File: sipp, Node: The wood shader, Next: The bozo shader, Prev: The granite shader, Up: Provided shaders
The wood shader
---------------
`wood_shader()' creates a simulated wood texture on a surface. It
uses two colors, one as the base (often lighter) color of the wood and
one as the color of the (often darker) rings in it. The rings are put
into the base color about the x-axis and are then distorted slightly. A
similar pattern is repeated at regular intervals to create an illusion
of logs or boards.
Surface description:
typedef struct {
double ambient;
double specular;
double c3;
double scale;
Color base;
Color ring;
Color opacity;
} Wood_desc;
* `ambient, specular, c3' and `opacity' have the same meaning as in
`basic_shader()' (see *Note The basic shader::).
* `scale' describes how much the texture coordinates should be scaled
before applying the texture. When scaling get larger, the object
will get larger in comparison with the wood texture.
* `base' and `ring' are the colors in the wood.
File: sipp, Node: The bozo shader, Next: The mask shader, Prev: The wood shader, Up: Provided shaders
The bozo shader
---------------
`bozo_shader()' uses a random number, correlated with the three
dimensional texture coordinates, to chose a color from a fixed set. The
user supplies an array of colors to choose from.
Surface description:
typedef struct {
Color colors[];
int no_of_cols;
double ambient;
double specular;
double c3;
double scale;
Color opacity;
} Bozo_desc;
* `colors' are an array of colors with `no_of_cols' entries.
* `ambient, specular, c3' and `opacity' have the same meaning as in
`basic_shader()' (see *Note The basic shader::).
* `scale' describes how much the texture coordinates should be scaled
before applying the texture.
File: sipp, Node: The mask shader, Next: The bumpy shader, Prev: The bozo shader, Up: Provided shaders
The mask shader
---------------
`mask_shader()' uses a user provided decision function to mask
between two different shaders. The decision function is passed all three
texture coordinates and returns TRUE or FALSE.
The decision function should have the following interface:
bool
my_masker(mask, u, v, w)
my_mask_data *mask;
int u, v, w;
* `my_mask_data' is a pointer to any data structure that the decision
function needs. A common use for `mask_shader()' is to use a bitmap
to mask something onto a surface, in this case `my_mask_data' could
point to the bitmap itself.
* `u, v' and `w' is the interpolated texture coordinates sent to the
shader.
Surface description:
typedef struct {
Shader *t_shader;
void *t_surface;
Shader *f_shader;
void *f_surface;
void *mask_data;
bool (*masker)();
} Mask_desc;
* The shader `t_shader' and the surface description `t_surface' is
used to shade the surface whenever the decision function returns
TRUE.
* The shader `f_shader' and the surface description `f_surface' is
used to shade the surface whenever the decision function returns
FALSE.
* `mask_data' points to any data structure the decision function
need.
* `masker' is a pointer to the decision function.